/**
 * @file ds18b20.c
 * @author Ai-Thinker Seahi
 * @brief
 * @version 0.1
 * @date 2021-09-02
 *
 * @copyright Copyright (c) 2021
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/hw_timer.h"
#include "ds18b20.h"
#include "esp_log.h"
#include "app_mqtt.h"
#include "cJSON.h"
#include "esp_spi_flash.h"
#include "app_oled.h"
#define ds18b20_DQ 2
#define DS18B20_IO_SEL (1ULL << ds18b20_DQ)

static char* TAG = "DS18B20";
static bool time_flag = 0;
/**
 * @brief 定时回调函数
 *
 * @param arg
 */
static void hw_timer_callback1(void* arg)
{
    time_flag = 1;
}
/**
 * @brief 微秒级延时
 *
 * @param _us
 */
static void ds18b20_delay_us(int64_t _us)
{
    hw_timer_init(hw_timer_callback1, NULL);
    hw_timer_alarm_us(_us, false);
    while (!time_flag);
    time_flag = 0;
    hw_timer_deinit();
}
/**
 * @brief 设置ds18b20 DQ的模式
 *
 * @param status
 *  status =1: 输出模式  status=0: 输入模式
 */
static void ds18b20_set_mode(bool status)
{
    gpio_config_t ds18b20_io;
    ds18b20_io.intr_type = GPIO_INTR_DISABLE;
    ds18b20_io.pin_bit_mask = DS18B20_IO_SEL;
    ds18b20_io.pull_down_en = 0;
    ds18b20_io.pull_up_en = 0;

    if (status)
        ds18b20_io.mode = GPIO_MODE_OUTPUT;
    else ds18b20_io.mode = GPIO_MODE_INPUT;

    gpio_config(&ds18b20_io);
    gpio_set_level(ds18b20_DQ, 1);

}
/**
 * @brief ds1820 初始化
 *
 * @return int
 *  成功返回0 失败返回0
 */
static int ds18b20_init(void)
{
    int16_t cnt = 0;
    ds18b20_set_mode(OUTPUT);

    gpio_set_level(ds18b20_DQ, 0);
    ds18b20_delay_us(600);
    gpio_set_level(ds18b20_DQ, 1);
    ds18b20_set_mode(INPUT);
    while ((gpio_get_level(ds18b20_DQ)) && (cnt < 2)) {
        ds18b20_delay_us(200);
        cnt++;
    }
    if (cnt >= 4) {
        ESP_LOGE(TAG, "-----No ds18b20");
        return 1;
    }
    cnt = 0;
    while (!gpio_get_level(ds18b20_DQ) && (cnt < 4)) {
        ds18b20_delay_us(200);
        cnt++;
    }
    if (cnt >= 4) {
        ESP_LOGE(TAG, "-----ds18b20 abnormal");
        return 1;
    }
    //ESP_LOGI(TAG, "-----ds1820 OK");
    return 0;
}
/**
 * @brief ds18b20 写8位数据
 *
 * @param data 8位数据
 *
 */
u_int8_t byte = 0;
static void ds18b20_write_data(u_int8_t data)
{
    u_int8_t j = 0;
    ds18b20_set_mode(OUTPUT);
    for (size_t i = 0; i < 8; i++) {
        gpio_set_level(ds18b20_DQ, 0);
        j++;
        gpio_set_level(ds18b20_DQ, data & 0x01);
        ds18b20_delay_us(100);
        gpio_set_level(ds18b20_DQ, 1);
        data >>= 1;
    }
    j = 0;
    // ESP_LOGI(TAG, "write data success");
}
/**
 * @brief ds18b20 读数据
 *
 * @return u_int8_t
 */
static u_int8_t ds18b20_read_data(void)
{
    u_int8_t data = 0;
    int j = 0;
    for (size_t i = 8; i > 0; i--) {
        ds18b20_set_mode(OUTPUT);
        gpio_set_level(ds18b20_DQ, 0);
        j++;
        gpio_set_level(ds18b20_DQ, 1);
        j++;j++;j++;
        ds18b20_set_mode(INPUT);
        data = gpio_get_level(ds18b20_DQ);
        byte = (byte >> 1) | (data << 7);
        ds18b20_delay_us(48);
    }
    j = 0;
    return byte;
}
/**
 * @brief 发送命令让ds1820开始转换温度
 *
 */
static void ds18b20_chang_temp(void)
{
    ds18b20_init();
    vTaskDelay(1 / portTICK_RATE_MS);
    ds18b20_write_data(0xcc);
    ds18b20_write_data(0x44);
}
/**
 * @brief 发送读取温度命令
 *
 */
static void ds18b20_read_temp_cmd(void)
{
    ds18b20_init();
    vTaskDelay(1 / portTICK_RATE_MS);
    ds18b20_write_data(0xcc); //跳过ROM操作命令
    ds18b20_write_data(0xbe);
}
/**
 * @brief ds18b20 读取温度
 *
 * @return int 温度值
 */
int ds18b20_read_temp(void)
{
    int temp = 0;
    uint8_t tmh = 0, tml = 0;
    ds18b20_chang_temp();
    ds18b20_read_temp_cmd();
    tml = ds18b20_read_data();
    tmh = ds18b20_read_data();
    temp = tmh;
    temp <<= 8;
    temp |= tml;
    return (temp * 0.0625);
}
/**
 * @brief 创建 ds18b20 的json 数据
 *
 * @param temp 温度参数
 * @return char*
 *  返回json数据
 */

static char* ds18b20_json_data(int32_t temp)
{
    cJSON* Root = cJSON_CreateObject();
    cJSON* param = cJSON_CreateObject();

    cJSON_AddStringToObject(Root, "mothod", "thing.event.property.post");
    cJSON_AddNumberToObject(Root, "id", 123956);
    cJSON_AddNumberToObject(param, "temp", temp);
    cJSON_AddNumberToObject(param, "RGB", RGB_STATUS);
    cJSON_AddItemToObject(Root, "params", param);
    cJSON_AddStringToObject(Root, "version", "1.0.0");

    char* cjson_data = cJSON_PrintUnformatted(Root);

    cJSON_Delete(Root);
    return cjson_data;
}
/**
 * @brief ds18b20 读取任务
 *
 * @param arg
 */
void ds18b20_upCloud_Task(void* arg)
{
    int temp = 0;
    static char* cjson_data;
    for (;;) {
        while (!mqtt_connect && OLED_INIT_OK) vTaskDelay(10 / portTICK_RATE_MS);
        temp = ds18b20_read_temp();
        if (temp > 0 && temp < 85) {
            vTaskDelay(1000 / portTICK_RATE_MS);
            cjson_data = ds18b20_json_data(temp);
            ESP_LOGI(TAG, "%s", cjson_data);
            esp_mqtt_client_publish(my_client, My_PubTopic, cjson_data, strlen(cjson_data), 1, 0);
            memset(cjson_data, 0, 128);
            sprintf(cjson_data, "%d", temp);
            oled_show_str(94, 6, cjson_data);
            oled_display_ch(110, 6, 13);
        }
        printf("heap size:%d\r\n", esp_get_free_heap_size());//内存监控
        temp = 0;
        vTaskDelay(1000 / portTICK_RATE_MS);
        free(cjson_data);
    }
}
